package com.snails.permission.aop;

import android.content.Context;
import android.view.View;

import androidx.fragment.app.Fragment;

import com.snails.permission.PermissionRequestActivity;
import com.snails.permission.annotation.NeedPermission;
import com.snails.permission.annotation.PermissionCanceled;
import com.snails.permission.annotation.PermissionDenied;
import com.snails.permission.iface.IPermission;
import com.snails.permission.iface.ISnailsPermission;
import com.snails.permission.model.CancelBean;
import com.snails.permission.model.DenyBean;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

/**
 * @author lawrence
 * @date 2019-05-05 18:11
 */
@Aspect
public class PermissionAspect {

    private static final String PERMISSION_REQUEST_POINTCUT =
            "execution(@com.snails.permission.annotation.NeedPermission * *(..))";

    @Pointcut(PERMISSION_REQUEST_POINTCUT + " && @annotation(needPermission)")
    public void requestPermissionMethod(NeedPermission needPermission) {
    }

    @Around("requestPermissionMethod(needPermission)")
    public void AroundJoinPoint(final ProceedingJoinPoint joinPoint, NeedPermission needPermission) {
        final Object object = joinPoint.getThis();
        if (object == null) return;
        final Context ctx = getCtx(object);
        if (ctx == null || needPermission == null) return;

        final String[] permissions = needPermission.value();
        final int requestCode = needPermission.requestCode();
        PermissionRequestActivity.PermissionRequest(
                ctx, permissions, requestCode, newPermissionCallback(joinPoint));
    }

    /**
     * 获得Context
     */
    private Context getCtx(Object object) {
        if (object != null) {
            if (object instanceof Context) {
                return (Context) object;
            } else if (object instanceof View) {
                return ((View) object).getContext();
            } else if (object instanceof Fragment) {
                final Context ctx = ((Fragment) object).getContext();
                if (ctx != null) return ctx;
                return ((Fragment) object).getActivity();
            } else if (object instanceof ISnailsPermission) {
                return ((ISnailsPermission) object).getCtx();
            }
        }
        return null;
    }

    private IPermission newPermissionCallback(ProceedingJoinPoint joinPoint) {
        final Object object = joinPoint.getThis();
        return new IPermission() {
            @Override
            public void PermissionGranted() {
                permissionGranted(joinPoint);
            }
            @Override
            public void PermissionDenied(int requestCode, List<String> denyList) {
                permissionDenied(object, requestCode, denyList);
            }
            @Override
            public void PermissionCanceled(int requestCode) {
                permissionCanceled(object, requestCode);
            }
        };
    }

    /**
     * 已授予全部权限
     */
    private void permissionGranted(ProceedingJoinPoint joinPoint) {
        try {
            joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    /**
     * 权限被拒绝
     */
    private void permissionDenied(Object object, int requestCode, List<String> denyList) {
        Method[] methods = object != null ? object.getClass().getDeclaredMethods() : null;
        if (methods == null || methods.length == 0) return;
        for (Method method : methods) {
            //过滤不含自定义注解PermissionDenied的方法
            boolean isHasAnnotation = method.isAnnotationPresent(PermissionDenied.class);
            if (isHasAnnotation) {
                method.setAccessible(true); // 设置为可访问权限
                Class<?>[] types = method.getParameterTypes();  // 获取方法参数类型
                if (types == null || types.length != 1) return; // 无参，或参数长度不唯一的 返回
                PermissionDenied aInfo = method.getAnnotation(PermissionDenied.class);  // 获取方法上的注解
                if (aInfo == null) return;  // 得不到注释 返回
                final DenyBean bean = new DenyBean(requestCode, denyList);  // 构建方法调用参数
                try {
                    method.invoke(object, bean);    // 调用方法，并传递参数
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 权限取消
     */
    private void permissionCanceled(Object object, int requestCode) {
        Method[] methods = object != null ? object.getClass().getDeclaredMethods() : null;
        if (methods == null || methods.length == 0) return;
        for (Method method : methods) {
            //过滤不含自定义注解PermissionCanceled的方法
            boolean isHasAnnotation = method.isAnnotationPresent(PermissionCanceled.class);
            if (isHasAnnotation) {
                method.setAccessible(true); // 设置为可访问权限
                Class<?>[] types = method.getParameterTypes();  // 获取方法参数类型
                if (types == null || types.length != 1) return; // 无参，或参数长度不唯一的 返回
                PermissionCanceled aInfo = method.getAnnotation(PermissionCanceled.class);  // 获取方法上的注解
                if (aInfo == null) return;  // 得不到注释 返回
                final CancelBean bean = new CancelBean(requestCode);    // 构建方法调用参数
                try {
                    method.invoke(object, bean);    // 调用方法，并传递参数
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
